package com.fxsh.auth.util;

import com.fxsh.auth.model.LoginUser;
import lombok.extern.slf4j.Slf4j;
import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.MalformedClaimException;
import org.jose4j.jwt.consumer.ErrorCodes;
import org.jose4j.jwt.consumer.InvalidJwtException;
import org.jose4j.jwt.consumer.JwtConsumer;
import org.jose4j.jwt.consumer.JwtConsumerBuilder;
import org.jose4j.lang.JoseException;

import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;

/**
 * @Author: lrz
 * @Date: 2020/10/18:13:50
 */
@Slf4j
public class JwtUtils {
    public static String generateJWT(LoginUser user) throws UnsupportedEncodingException {
        SecretKeySpec key = new SecretKeySpec(("secretsecretsecretsecretsecretsecretsecretsecret").getBytes(StandardCharsets.UTF_8), AlgorithmIdentifiers.HMAC_SHA512);
        String jwt = "";
        try{
            JwtClaims claims = new JwtClaims();
            claims.setIssuer("AuthCenter"); // 令牌生产方
            claims.setAudience("web"); // 令牌使用方
            claims.setExpirationTimeMinutesInTheFuture(10);
            claims.setGeneratedJwtId();
            claims.setIssuedAtToNow();
            claims.setSubject("Authenticate");
            claims.setNotBeforeMinutesInThePast(2);
            claims.setClaim("userName",user.getName());

            JsonWebSignature jsonWebSignature = new JsonWebSignature();
            jsonWebSignature.setPayload(claims.toJson());

            jsonWebSignature.setKey(key);
            jsonWebSignature.setAlgorithmHeaderValue(AlgorithmIdentifiers.HMAC_SHA256);

            jwt = jsonWebSignature.getCompactSerialization();
        }catch (JoseException e){
            e.printStackTrace();
        }
        return jwt;
    }

    public static JwtClaims validJwt(String jwt) throws UnsupportedEncodingException {
        JwtClaims jwtClaims = null;
        JwtConsumer jwtConsumer = new JwtConsumerBuilder()
                .setRequireExpirationTime() // the JWT must have an expiration time
                .setAllowedClockSkewInSeconds(30) // allow some leeway in validating time based claims to account for clock skew
                .setRequireSubject() // the JWT must have a subject claim
                .setExpectedIssuer("AuthCenter") // whom the JWT needs to have been issued by
                .setExpectedAudience("web") // to whom the JWT is intended for
                .setVerificationKey(new SecretKeySpec(("secretsecretsecretsecretsecretsecretsecretsecret").getBytes(StandardCharsets.UTF_8), AlgorithmIdentifiers.HMAC_SHA512)) // verify the signature with the public key
                .setRelaxVerificationKeyValidation()
                .build(); // create the JwtConsumer instance
        try
        {
            //  Validate the JWT and process it to the Claims
            jwtClaims = jwtConsumer.processToClaims(jwt);
        }
        catch (InvalidJwtException e)
        {
            // InvalidJwtException will be thrown, if the JWT failed processing or validation in anyway.
            // Hopefully with meaningful explanations(s) about what went wrong.
            System.out.println("Invalid JWT! " + e);

            // Programmatic access to (some) specific reasons for JWT invalidity is also possible
            // should you want different error handling behavior for certain conditions.

            // Whether or not the JWT has expired being one common reason for invalidity
            if (e.hasExpired())
            {
                try {
                    System.out.println("JWT expired at " + e.getJwtContext().getJwtClaims().getExpirationTime());
                } catch (MalformedClaimException malformedClaimException) {
                    malformedClaimException.printStackTrace();
                }
            }

            // Or maybe the audience was invalid
            if (e.hasErrorCode(ErrorCodes.AUDIENCE_INVALID))
            {
                try {
                    System.out.println("JWT had wrong audience: " + e.getJwtContext().getJwtClaims().getAudience());
                } catch (MalformedClaimException malformedClaimException) {
                    malformedClaimException.printStackTrace();
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return jwtClaims;
    }
}
